#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <thread>
#include <vector>

typedef struct CFD
{
    int fd;
    int id;
} CFD;

/*Global vars*/
int CFD_COUNTER = 0;
std::vector<CFD> CFD_BUFFER;

void *Work(void *arg)
{
    CFD cfd_this;
    cfd_this.fd = ((CFD *)arg)->fd;
    cfd_this.id = ((CFD *)arg)->id;
    /*Recv data*/
    while (true)
    {
        char buf[1024];
        memset(buf, 0, sizeof(buf));
        int len = read(cfd_this.fd, buf, sizeof(buf));
        if (len > 0)
        {
#if 0
            printf("Client say(%d):", len);
            for (int i = 0; i < len; i++)
            {
                printf("0x%02X ", buf[i]);
            }
            printf("\n");
#endif
            /*Send data to other*/
            for (int i = 0; i < CFD_BUFFER.size(); i++)
            {
                if (CFD_BUFFER[i].id == cfd_this.id)
                {
                    continue;
                }

                send(CFD_BUFFER[i].fd, buf, len, 0);
            }
        }
        else if (len == 0)
        {
            printf("Client disconnected!\n");
            break;
        }
        else
        {
            printf("Error : Read failed!\n");
            break;
        }
    }
    /*Eraser self*/
    std::vector<CFD>::iterator it = CFD_BUFFER.begin();
    for (; it < CFD_BUFFER.end(); it++)
    {
        if (it->id == cfd_this.id)
        {
            it = CFD_BUFFER.erase(it);
        }
    }
    return NULL;
}

int main()
{
    /*Create socket*/
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if (lfd == -1)
    {
        printf("Error : Create socket failed!\n");
        return -1;
    }
    printf("Create socket OK!\n");

    /*Config ip and port*/
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(50000);
    addr.sin_addr.s_addr = INADDR_ANY;

    /*Bind port with socket*/
    int ret = bind(lfd, (const sockaddr *)&addr, sizeof(addr));
    if (ret == -1)
    {
        printf("Error : Bind failed!\n");
        return -1;
    }
    printf("Bind port OK!\n");

    /*Config listen*/
    ret = listen(lfd, 128);
    if (ret == -1)
    {
        printf("Error : Listen failed!\n");
        return -1;
    }
    printf("Config listen OK!\n");

    while (true)
    {

        /*Wait for client*/
        printf("Waiting for client...\n");
        struct sockaddr_in cliaddr;
        int clilen = sizeof(cliaddr);
        int cfd = accept(lfd, (struct sockaddr *)&cliaddr, (socklen_t *)&clilen);
        if (cfd == -1)
        {
            printf("Error : Accept failed!\n");
            return -1;
        }

        /*Print information of new client*/
        char ip[24] = {0};
        inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, ip, sizeof(ip));
        printf("New client from %s:%d", ip, ntohs(cliaddr.sin_port));

        /*Start work thread*/
        CFD fd_new;
        fd_new.fd = cfd;
        fd_new.id = CFD_COUNTER;
        CFD_BUFFER.push_back(fd_new);
        CFD_COUNTER++;
        new std::thread([=]()
                        { Work((void *)&fd_new); });
    }
    return 0;
}